package JavaFoundation.myLock.volataileTest;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

class myDate{
    volatile int number = 0;
    AtomicInteger atomicInteger = new AtomicInteger();
    public void addNumber(){ this.number = 60; }
    //此时number有volatile修饰
    public synchronized void addPlusPlus(){number++;}//加synchronized可以保证数据的原子性
    public void addPlusAtomicInteger(){ atomicInteger.getAndIncrement();}
}

public class ValitaleTest {
    public static void main(String[] args) {
        test3();
    }
    public static void test3(){
        myDate myDate = new myDate();
        System.out.println("==============="+myDate.atomicInteger);
        for (int i = 1; i <= 20; i++) {
            new Thread(()->{
                for (int j = 1; j <= 1000; j++) {
                    myDate.addPlusAtomicInteger();
                }
            },String.valueOf(i)).start();
        }
        while (Thread.activeCount()>2){
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName()+"==="+myDate.atomicInteger);

    }


    //验证volatile不保证原子性
    /*
    原子性：保证数据的完整性，中间不可被打断,在多线程并发的情况下number最终的值很难是20000.
    why? i++包含三个步骤，从主内存中读取值，拷贝到自己的内存中修改，然后在写回主物理内存。
        虽然有volatile修饰，但由于并发的线程太快，有可能有线程在写操作的时候被挂起，会造成数据丢失的情况。
        解决volatile的原子性可以用synchronized。
        也可用juc下 atomicInteger
     */
    public static void test2(){
        myDate myDate = new myDate();
        for (int i = 1; i <= 20; i++) {
            new Thread(()->{
                for (int j = 1; j <= 1000; j++) {
                    myDate.addPlusPlus();
                }
            },String.valueOf(i)).start();
        }
        while (Thread.activeCount()>2){
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName()+"==="+myDate.number);
    }

    //验证volatile的内存可见性
    public static void test1(){
        myDate myDate = new myDate();
        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"/t com in");
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
            myDate.addNumber();
            System.out.println(Thread.currentThread().getName()+"/t update number="+myDate.number);
        },"AAA").start();

        while (myDate.number == 0){
            //
        }
        System.out.println("保证内存可见性后才会输出===");
    }

}
